/*
 * SessionDemo.cpp
 *
 *  Created on: 2011-8-10
 *      Author: hywie
 */
#include "SessionDemo.h"
#include <stdlib.h>
#include <regex.h>

void *thread_recv(void *lpParm)
{
	ClientClass *client = (ClientClass *)lpParm;	//得到与该客户端对应的ClientClass对象
	int len;
	int client_fd;
	client_fd = client->getSock_fd();	//得到服务器与该客户端进行通信的套接字

	char buff[MAXSIZE];
	len = recv(client_fd, buff, sizeof(buff), 0);	//接收来自客户端的登录消息
	buff[len] = '\0';
	string loginMsg = buff;

	string patten = "^ID:[0-9]*PWD:([0-9]|[A-Z]|[a-z])*#";	//设置正则表达式,检测登录消息内容格式是否正确
	if(!matchFunc(patten, loginMsg))		//格式不正确
	{
		string error = "登录信息格式错误";
		send(client_fd, error.c_str(), error.size(), 0);		//向客户端发送错误信息
		close(client_fd);		//关闭套接字
		return NULL;
	}
//	string loginMsg = "ID:791342685PWD:15071339704XUwei#";	//正确的登录消息格式
	int pos1, pos2, pos3;
	pos1 = loginMsg.find(':', 0);
	pos2 = loginMsg.find(':', pos1+1);
	pos3 = loginMsg.find('#', pos2);
	string str_id = loginMsg.substr(pos1+1, pos2-pos1-4);		//得到登录帐号
	string str_pwd = loginMsg.substr(pos2+1, pos3-pos2-1);	//得到登录密码

	int id = atoi(str_id.c_str());	//登录帐号由字符串转整型
	string str_name;
	bool bFlag = client->getDBClass()->checkUser(id, str_pwd, str_name);	//检测登录信息是否正确
	if(!bFlag)	//验证失败
	{
		string sendMsg = "ERROR";
		send(client_fd, sendMsg.c_str(), sendMsg.length(), 0);	//向客户端发送登录失败消息
		close(client_fd);		//关闭套接字
		return NULL;
	}
	else
	{
		string sendMsg = "OK.";
		send(client_fd, sendMsg.c_str(), sendMsg.length(), 0);	//向客户端发送登录成功消息
		send(client_fd, str_name.c_str(), str_name.length(), 0);	//向客户端发送用户昵称
	}
	client->getDBClass()->socketAdd(id, client_fd);		//新增用户,记录该用户帐号id和套接字client_fd
	onlineFunc(client);	//向该新登录的用户发送所有当前在线用户的信息
	struct def_msg msg;
	while(1)
	{
		memset(&msg, 0, sizeof(msg));
		len = recv(client_fd, (char *)&msg, sizeof(msg), 0);	//接收来自该客户端的消息
		if(len <= 0)	//检测到套接字关闭,退出循环
			break;
		if(strcmp(msg.msg_type, CHAT) == 0)		//聊天消息
		{
			client->getDBClass()->radioOneMessage(msg);	//向所有在线用户转发该消息
		}
	}
	close(client_fd);	//关闭套接字
	client->getDBClass()->downlineRemove(id);	//用户下线,更新用户信息集合
	strcpy(msg.msg_type, DOWNLINE);	//设置消息类型--"下线消息"
	string str = str_name + "(" + str_id + ")";	//设置内容格式
	strcpy(msg.msg_buf, str.c_str());	//设置消息内容
	client->getDBClass()->radioOneMessage(msg);	//向所有在线用户广播该用户的下线消息
	return NULL;
}

bool matchFunc(string patten, string str)		//检测登录消息格式是否正确
{
	int rnt;
	bool bFlag;
	regex_t reg;
	rnt = regcomp(&reg, patten.c_str(), REG_NOSUB | REG_EXTENDED | REG_ICASE);
	if(rnt)
	{
		return false;
	}
	rnt = regexec(&reg, str.c_str(), 0, NULL, 0);
	if(rnt == REG_NOERROR)	//正确匹配,说明格式正确,返回true
	{
		bFlag = true;
	}
	else		//匹配失败,消息格式错误,返回false
	{
		bFlag = false;
	}
	regfree(&reg);
	return bFlag;
}

void onlineFunc(ClientClass *client)
{
	string str_all, str_one;
	str_all = client->getDBClass()->getAllUsers();	//得到当前所有在线用户的信息
	int pos1, pos2, length;
	int client_fd = client->getSock_fd();	//得到当前用户的通信套接字
	struct def_msg msg;
	strcpy(msg.msg_type, ONLINE);		//设置消息类型--"上线消息"
	pos1 = 0;
	pos2 = 0;
	length = str_all.length();
	while(pos2+1 < length)
	{
		pos2 = str_all.find(';', pos1);
		str_one = str_all.substr(pos1, pos2-pos1);
		strcpy(msg.msg_buf, str_one.c_str());	//设置消息内容
		send(client_fd, (char *)&msg, sizeof(msg), 0);	//循环向该新登录的用户发送所有在线用户的信息
		pos1 = pos2+1;
	}
}
